// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;

using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.WindowsRuntime;

namespace System.Runtime.InteropServices
{
    // Shared CCW Design (fyuan, 6/26/2013)

    // Normal CCW is implemented by constructing a native virtual function table with specific functions for each interface using MCG generated code.
    // For each CCW interface, there is a native class e.g. internal unsafe partial struct __vtable_Windows_ApplicationModel_Resources_Core__IResourceContext
    // Static field s_theCcwVtable constructs the virtual function table, whose address is stored in McgInterfaceData.CcwVtable field.
    // Each function within vtable is marked as [NativeCallable]. It has marsalling code and exception handling to set COM HRESULT.

    // During runtime __interface_ccw.Allocate allocates a small piece of native memory and constructs the real CCW callable by native code

    // Shared CCW is supported on generic interfaces, sharable across multiple instances of supported interfaces.
    // For example SharedCcw_IVector supports all IVector<T> CCW where T is a reference type using a single copy of code.
    // But to support individual element types, we need extra information about each element type and a thunk function to call real methods on interface instantiations.

    // Information about element type is encoded in McgGenericArgumentMarshalInfo struct per element type. McgInterfaceData has an added index MarshalIndex indexing into the table.
    // When constructing __inteface_ccw, an extra field m_pInterface is added to point back to McgInterfaceData, from which we can get McgGenericArgumentMarshalInfo.

    // Each CCW interface supported by shared CCW has a thunk function which is normally an instance of a generic function. The function is set use the SetThunk function generated by MCG

    // From a native CCW pointer, ComCallableObject.GetThunk functions returns target object, marshal index, and thunk function.
    // Shared CCW code can use marshal index to marshal objects between native and managed worlds, and use thunk function to invoke functions on corresponding managed code.
    // It also handles semantics of wrapper classes like ListToVectorAdapter for argument checking and exception -> HRESULT translation

    // Here is a example:
    //   1) SharedCCW_IVector supports IVector<T> where T is reference type
    //   2) Its thunk function is int IListThunk<T>(IList<T> list, IList_Oper oper, int index, ref object item).
    //   3) Thunk function handles 9 basic operations on IList<T>: GetCount, GetItem, IndexOf, SetItem, Insert, RemoveAt, Add, Clear, and ToReadOnly
    //   4) Functions in SharedCCW_IVector handles [NativeCallable] protocol, getting thunk information, marshalling, invoking thunk function, and exception handling.
    //   5) For a particular element type, say string, IListThunk<string> dispatches to basic operations on IList<string>.
    //   6) Due to generic code sharing, there is a real implementation of IListThunk<Canon> and IListThunk<string> just calls it with the right 'Generic Dictionary'

    /* Code generated by MCG for 4 shared CCW instances: IEnumerable<string> (IIterable), IIterator<T>, IList<T>(IVector), and IReadOnlyList<T>(IVectorView)

        SetThunk(35, AddrOfIntrinsics.AddrOf(Toolbox.IEnumerableThunk<string>));
        SetThunk(36, AddrOfIntrinsics.AddrOf(Toolbox.IIteratorThunk<string>));
        SetThunk(69, AddrOfIntrinsics.AddrOf(System.Runtime.InteropServices.Toolbox.IListThunk<string>));
        SetThunk(70, AddrOfIntrinsics.AddrOf(System.Runtime.InteropServices.Toolbox.IReadOnlyListThunk<string>));

        new McgGenericArgumentMarshalInfo() {  // index: 2, 'string' => 'HSTRING $'
            ElementClassIndex     = -1,
            ElementInterfaceIndex = s_McgTypeInfoIndex___com_HSTRING,
            VectorViewIndex       = s_McgTypeInfoIndex___com_Windows_Foundation_Collections__IVectorView_A_string_V_,
            IteratorIndex         = s_McgTypeInfoIndex___com_Windows_Foundation_Collections__IIterator_A_string_V_, },

        new McgInterfaceData() { ... // index: 35, System.Collections.Generic.IEnumerable<string>
            MarshalIndex = 2,
            Flags = McgInterfaceFlags.isIInspectable | McgInterfaceFlags.useSharedCCW_IIterable, },

        new McgInterfaceData() { ... // index: 36, Windows.Foundation.Collections.IIterator<string>
            MarshalIndex = 2,
            Flags = McgInterfaceFlags.isIInspectable | McgInterfaceFlags.useSharedCCW_IIterator, },

        new McgInterfaceData() { ... // index: 69, System.Collections.Generic.IList<string>
            MarshalIndex = 2,
            Flags = McgInterfaceFlags.isIInspectable | McgInterfaceFlags.useSharedCCW_IVector, },

        new McgInterfaceData() { ... // index: 70, System.Collections.Generic.IReadOnlyList<string>
            MarshalIndex = 2,
            Flags = McgInterfaceFlags.isIInspectable | McgInterfaceFlags.useSharedCCW_IVectorView, },
    */

    public static partial class Toolbox
    {
        // Basic operations on IList/IReadOnlyList to support IVector/IVectorView
        public enum IList_Oper
        {
            GetCount,
            GetItem,
            IndexOf,

            SetItem,
            Insert,
            RemoveAt,
            Add,
            Clear,
            ToReadOnly
        };

        /// <summary>
        /// Static thunk function for calling methods on IList<T>
        /// </summary>
        public static int IListThunk<T>(IList<T> list, IList_Oper oper, int index, ref object item) where T : class
        {
            int result = 0;

            switch (oper)
            {
                case IList_Oper.GetCount:
                    result = list.Count;
                    break;

                case IList_Oper.GetItem:
                    item = list[index];
                    break;

                case IList_Oper.IndexOf:
                    result = list.IndexOf(InteropExtensions.UncheckedCast<T>(item));
                    break;

                case IList_Oper.SetItem:
                    list[index] = InteropExtensions.UncheckedCast<T>(item);
                    break;

                case IList_Oper.Insert:
                    list.Insert(index, InteropExtensions.UncheckedCast<T>(item));
                    break;

                case IList_Oper.RemoveAt:
                    list.RemoveAt(index);
                    break;

                case IList_Oper.Add:
                    list.Add(InteropExtensions.UncheckedCast<T>(item));
                    break;

                case IList_Oper.Clear:
                    list.Clear();
                    break;

                case IList_Oper.ToReadOnly:
                    {
                        IReadOnlyList<T> view;

                        // Note: This list is not really read-only - you could QI for a modifiable
                        // list.  We gain some perf by doing this.  We believe this is acceptable.
                        view = list as IReadOnlyList<T>;

                        if (view == null)
                        {
                            view = new System.Collections.ObjectModel.ReadOnlyCollection<T>(list);
                        }

                        item = view; // return via item
                    }
                    break;

                default:
                    Debug.Fail("IListThunk wrong oper");
                    break;
            }

            return result;
        }

        /// <summary>
        /// Static thunk function for calling methods on IList<T>
        /// </summary>
        public static object IListBlittableThunk<T>(IList<T> list, IList_Oper oper, ref int index, ref T item) where T : struct
        {
            object result = null;

            switch (oper)
            {
                case IList_Oper.GetCount:
                    index = list.Count;
                    break;

                case IList_Oper.GetItem:
                    item = list[index];
                    break;

                case IList_Oper.IndexOf:
                    index = list.IndexOf(item);
                    break;

                case IList_Oper.SetItem:
                    list[index] = item;
                    break;

                case IList_Oper.Insert:
                    list.Insert(index, item);
                    break;

                case IList_Oper.RemoveAt:
                    list.RemoveAt(index);
                    break;

                case IList_Oper.Add:
                    list.Add(item);
                    break;

                case IList_Oper.Clear:
                    list.Clear();
                    break;

                case IList_Oper.ToReadOnly:
                    {
                        // Note: This list is not really read-only - you could QI for a modifiable
                        // list.  We gain some perf by doing this.  We believe this is acceptable.
                        result = list as IReadOnlyList<T>;

                        if (result == null)
                        {
                            result = new System.Collections.ObjectModel.ReadOnlyCollection<T>(list);
                        }
                    }
                    break;

                default:
                    Debug.Fail("IListBlittableThunk wrong oper");
                    break;
            }

            return result;
        }

        internal static bool EnsureIndexInt32(uint index, uint listCapacity, ref int hr)
        {
            // We use '<=' and not '<' becasue Int32.MaxValue == index would imply
            // that Size > Int32.MaxValue:
            if (((uint)System.Int32.MaxValue) <= index || index >= listCapacity)
            {
                hr = Interop.COM.E_BOUNDS;

                return false;
            }

            return true;
        }

        /// <summary>
        /// Static thunk function for calling methods on IReadOnlyList<T>
        /// </summary>
        public static int IReadOnlyListThunk<T>(IReadOnlyList<T> list, IList_Oper oper, int index, ref T item) where T : class
        {
            int result = 0;

            switch (oper)
            {
                case IList_Oper.GetCount:
                    result = list.Count;
                    break;

                case IList_Oper.GetItem:
                    item = list[index];
                    break;

                case IList_Oper.IndexOf:
                    {
                        result = -1;

                        index = list.Count;

                        for (int i = 0; i < index; i++)
                        {
                            if (InteropExtensions.ComparerEquals<T>(item, list[i]))
                            {
                                result = i;
                                break;
                            }
                        }
                    }
                    break;

                default:
                    Debug.Fail("IReadOnlyListThunk wrong oper");
                    break;
            }

            return result;
        }

        /// <summary>
        /// Static thunk function for calling methods on IReadOnlyList<T>
        /// </summary>
        public static object IReadOnlyListBlittableThunk<T>(IReadOnlyList<T> list, IList_Oper oper, ref int index, ref T item) where T : struct
        {
            object result = null;

            switch (oper)
            {
                case IList_Oper.GetCount:
                    index = list.Count;
                    break;

                case IList_Oper.GetItem:
                    item = list[index];
                    break;

                case IList_Oper.IndexOf:
                    {
                        index = -1;

                        int count = list.Count;

                        for (int i = 0; i < count; i++)
                        {
                            if (InteropExtensions.ComparerEquals<T>(item, list[i]))
                            {
                                index = i;
                                break;
                            }
                        }
                    }
                    break;

                default:
                    Debug.Fail("IReadOnlyListThunk wrong oper");
                    break;
            }

            return result;
        }
    }

#if ENABLE_MIN_WINRT

    /// <summary>
    /// Shared CCW for IVector<T> over IList<T> where T is a reference type marshalled to COM interface
    /// </summary>
    internal unsafe struct SharedCcw_IVector
    {
        public System.IntPtr pfnQueryInterface;
        public System.IntPtr pfnAddRef;
        public System.IntPtr pfnRelease;
        public System.IntPtr pfnGetIids;
        public System.IntPtr pfnGetRuntimeClassName;
        public System.IntPtr pfnGetTrustLevel;

        public System.IntPtr pfnGetAt;
        public System.IntPtr pfnget_Size;
        public System.IntPtr pfnGetView;
        public System.IntPtr pfnIndexOf;
        public System.IntPtr pfnSetAt;
        public System.IntPtr pfnInsertAt;
        public System.IntPtr pfnRemoveAt;
        public System.IntPtr pfnAppend;
        public System.IntPtr pfnRemoveAtEnd;
        public System.IntPtr pfnClear;
        public System.IntPtr pfnGetMany;
        public System.IntPtr pfnReplaceAll;

        [PreInitialized]
        static SharedCcw_IVector s_theCcwVtable = new SharedCcw_IVector()
        {
            pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
            pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
            pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
            pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
            pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
            pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),

            pfnGetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(GetAt),
            pfnget_Size = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_Size),
            pfnGetView = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(GetView),
            pfnIndexOf = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIndexOf>(IndexOf),
            pfnSetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(SetAt),
            pfnInsertAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(InsertAt),
            pfnRemoveAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfRemoveAt>(RemoveAt),
            pfnAppend = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(Append),
            pfnRemoveAtEnd = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(RemoveAtEnd),
            pfnClear = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(Clear),
            pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany1>(GetMany),
            pfnReplaceAll = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(ReplaceAll),
        };

        public static System.IntPtr GetVtable()
        {
            return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
        }

        [NativeCallable]
        internal static unsafe int GetAt(IntPtr pComThis, uint index, IntPtr pItem)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object item = null;
                CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetItem, (int)index, ref item);

                *((IntPtr*)pItem) = McgMarshal.ObjectToComInterface(item, interfaceType.GetElementInterfaceType());
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }

        [NativeCallable]
        internal static unsafe int get_Size(System.IntPtr pComThis, System.IntPtr pSize)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object dummy = null;

                *((uint*)pSize) = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref dummy);
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static unsafe int GetView(System.IntPtr pComThis, System.IntPtr pView)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object view = null;

                CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.ToReadOnly, 0, ref view);

                *((IntPtr*)pView) = McgMarshal.ObjectToComInterface(view, interfaceType.GetVectorViewType());
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }


        [NativeCallable]
        internal static unsafe int IndexOf(System.IntPtr pComThis, System.IntPtr _value, System.IntPtr pIndex, System.IntPtr pFound)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object value = McgMarshal.ComInterfaceToObject(_value, interfaceType.GetElementInterfaceType(), interfaceType.GetElementClassType());

                int index = CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.IndexOf, 0, ref value);

                if (index >= 0)
                {
                    *((byte*)pFound) = 1;
                }
                else
                {
                    *((byte*)pFound) = 0;

                    index = 0;
                }

                *((int*)pIndex) = index;
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static unsafe int SetAt(System.IntPtr pComThis, uint index, IntPtr _value)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object value = null;

                uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref value);

                if (Toolbox.EnsureIndexInt32(index, listCount, ref hr))
                {
                    value = McgMarshal.ComInterfaceToObject(_value, interfaceType.GetElementInterfaceType(), interfaceType.GetElementClassType());

                    CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.SetItem, (int)index, ref value);
                }
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }


        [NativeCallable]
        static unsafe int InsertAt(System.IntPtr pComThis, uint index, IntPtr _value)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object value = null;

                uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref value);

                // Inserting at an index one past the end of the list is equivalent to appending
                // so we need to ensure that we're within (0, count + 1).
                if (Toolbox.EnsureIndexInt32(index, listCount + 1, ref hr))
                {
                    value = McgMarshal.ComInterfaceToObject(_value, interfaceType.GetElementInterfaceType(), interfaceType.GetElementClassType());

                    CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Insert, (int)index, ref value);
                }
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }

        [NativeCallable]
        static unsafe int RemoveAt(System.IntPtr pComThis, uint index)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object dummy = null;
                uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref dummy);

                if (Toolbox.EnsureIndexInt32(index, listCount, ref hr))
                {
                    CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.RemoveAt, (int)index, ref dummy);
                }
            }

            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }


        [NativeCallable]
        static unsafe int Append(System.IntPtr pComThis, IntPtr _value)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object value = McgMarshal.ComInterfaceToObject(_value, interfaceType.GetElementInterfaceType(), interfaceType.GetElementClassType());

                CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Add, 0, ref value);
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }


        [NativeCallable]
        static unsafe int RemoveAtEnd(System.IntPtr pComThis)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object dummy = null;

                uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref dummy);

                if (listCount == 0)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
                else
                {
                    CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.RemoveAt, (int)(listCount - 1), ref dummy);
                }
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }


        [NativeCallable]
        static unsafe int Clear(System.IntPtr pComThis)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object dummy = null;

                CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Clear, 0, ref dummy);
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }


        [NativeCallable]
        internal static unsafe int GetMany(System.IntPtr pComThis, uint startIndex, uint len, System.IntPtr pDest, System.IntPtr pCount)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object value = null;

                uint listCount = (uint)CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetCount, 0, ref value);

                uint itemCount = 0;

                if ((startIndex != listCount) && Toolbox.EnsureIndexInt32(startIndex, listCount, ref hr))
                {
                    itemCount = System.Math.Min(len, listCount - startIndex);

                    System.IntPtr* dst = (System.IntPtr*)pDest;

                    // Convert to COM interfaces, without allocating array
                    uint i = 0;

                    while (i < itemCount)
                    {
                        CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.GetItem, (int)(i + startIndex), ref value);

                        dst[i] = McgMarshal.ObjectToComInterface(value, interfaceType.GetElementInterfaceType());

                        i++;
                    }

                    // Fill the remaining with default value
                    while (i < len)
                    {
                        dst[i++] = default(IntPtr);
                    }
                }

                *((uint*)pCount) = itemCount;
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static unsafe int ReplaceAll(System.IntPtr pComThis, uint length, IntPtr pItems)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get Target Object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                System.IntPtr* src = (System.IntPtr*)pItems;

                object value = null;

                CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Clear, 0, ref value);

                for (uint i = 0; i < length; i++)
                {
                    value = McgMarshal.ComInterfaceToObject(src[i],  interfaceType.GetElementInterfaceType(), interfaceType.GetElementClassType());

                    CalliIntrinsics.Call<int>(thunk, list, Toolbox.IList_Oper.Add, 0, ref value);
                }
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }
    }

    /// <summary>
    /// Shared CCW for IVector<T> over IList<T> where T is a blittable struct
    /// </summary>
    internal unsafe struct SharedCcw_IVector_Blittable
    {
        public System.IntPtr pfnQueryInterface;
        public System.IntPtr pfnAddRef;
        public System.IntPtr pfnRelease;
        public System.IntPtr pfnGetIids;
        public System.IntPtr pfnGetRuntimeClassName;
        public System.IntPtr pfnGetTrustLevel;

        public System.IntPtr pfnGetAt;
        public System.IntPtr pfnget_Size;
        public System.IntPtr pfnGetView;
        public System.IntPtr pfnIndexOf;
        public System.IntPtr pfnSetAt;
        public System.IntPtr pfnInsertAt;
        public System.IntPtr pfnRemoveAt;
        public System.IntPtr pfnAppend;
        public System.IntPtr pfnRemoveAtEnd;
        public System.IntPtr pfnClear;
        public System.IntPtr pfnGetMany;
        public System.IntPtr pfnReplaceAll;

        [PreInitialized]
        static SharedCcw_IVector_Blittable s_theCcwVtable = new SharedCcw_IVector_Blittable()
        {
            pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
            pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
            pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
            pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
            pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
            pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),

            pfnGetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(GetAt),
            pfnget_Size = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_Size),
            pfnGetView = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(GetView),
            pfnIndexOf = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIndexOf>(IndexOf),
            pfnSetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(SetAt),
            pfnInsertAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(InsertAt),
            pfnRemoveAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfRemoveAt>(RemoveAt),
            pfnAppend = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(Append),
            pfnRemoveAtEnd = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(RemoveAtEnd),
            pfnClear = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget1>(Clear),
            pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany1>(GetMany),
            pfnReplaceAll = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(ReplaceAll),
        };

        public static System.IntPtr GetVtable()
        {
            return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
        }

        [NativeCallable]
        internal static unsafe int GetAt(IntPtr pComThis, uint _index, IntPtr pItem)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int index = (int)_index;

                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetItem, ref index, pItem);
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }

        [NativeCallable]
        internal static unsafe int get_Size(System.IntPtr pComThis, System.IntPtr pSize)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int size = 0;
                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetCount, ref size, default(IntPtr));

                *((uint*)pSize) = (uint)size;
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static unsafe int GetView(System.IntPtr pComThis, System.IntPtr pView)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int dummy = 0;
                object view = CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.ToReadOnly, ref dummy, default(IntPtr));

                *((IntPtr*)pView) = McgMarshal.ObjectToComInterface(view, interfaceType.GetVectorViewType());
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }


        [NativeCallable]
        internal static unsafe int IndexOf(System.IntPtr pComThis, System.IntPtr _value, System.IntPtr pIndex, System.IntPtr pFound)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int index = 0;
                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.IndexOf, ref index, (IntPtr)(&_value));

                if (index >= 0)
                {
                    *((byte*)pFound) = 1;
                }
                else
                {
                    *((byte*)pFound) = 0;

                    index = 0;
                }

                *((int*)pIndex) = index;
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static unsafe int SetAt(System.IntPtr pComThis, uint _index, IntPtr _value)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int index = (int)_index;
                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.SetItem, ref index, (IntPtr)(&_value));
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }


        [NativeCallable]
        static unsafe int InsertAt(System.IntPtr pComThis, uint _index, IntPtr _value)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int index = (int)_index;

                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Insert, ref index, (IntPtr)(&_value));
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }

        [NativeCallable]
        static unsafe int RemoveAt(System.IntPtr pComThis, uint _index)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int index = (int)_index;

                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.RemoveAt, ref index, default(IntPtr));
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }


        [NativeCallable]
        static unsafe int Append(System.IntPtr pComThis, IntPtr _value)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int dummy = 0;

                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Add, ref dummy, (IntPtr)(&_value));
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }


        [NativeCallable]
        static unsafe int RemoveAtEnd(System.IntPtr pComThis)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int index = 0;

                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetCount, ref index, default(IntPtr));

                if (index == 0)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
                else
                {
                    index--;

                    CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.RemoveAt, ref index, default(IntPtr));
                }
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
                if (hrExcep is ArgumentOutOfRangeException)
                {
                    hr = Interop.COM.E_BOUNDS;
                }
            }

            return hr;
        }


        [NativeCallable]
        static unsafe int Clear(System.IntPtr pComThis)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int dummy = 0;
                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Clear, ref dummy, default(IntPtr));
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }


        [NativeCallable]
        internal static unsafe int GetMany(System.IntPtr pComThis, uint startIndex, uint len, System.IntPtr pDest, System.IntPtr pCount)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int listCount = 0;

                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetCount, ref listCount, default(IntPtr));

                uint itemCount = 0;

                if ((startIndex != listCount) && Toolbox.EnsureIndexInt32(startIndex, (uint)listCount, ref hr))
                {
                    itemCount = System.Math.Min(len, (uint)listCount - startIndex);

                    // Convert to COM interfaces, without allocating array
                    uint i = 0;

                    int byteSize = interfaceType.GetByteSize();

                    while (i < itemCount)
                    {
                        int index = (int)(i + startIndex);

                        CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.GetItem, ref index, pDest);

                        pDest = (IntPtr)((byte*)pDest + byteSize);

                        i++;
                    }
                }

                *((uint*)pCount) = itemCount;
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static unsafe int ReplaceAll(System.IntPtr pComThis, uint length, IntPtr pItems)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get IList object
                object list = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int dummy = 0;

                CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Clear, ref dummy, default(IntPtr));

                int byteSize = interfaceType.GetByteSize();

                for (uint i = 0; i < length; i++)
                {
                    CalliIntrinsics.Call<object>(thunk, list, Toolbox.IList_Oper.Add, ref dummy, pItems);

                    pItems = (IntPtr)((byte*)pItems + byteSize);
                }
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }
    }

    /// <summary>
    /// Shared CCW for IVectorView<T> over IReadOnlyList<T> where T is a reference type marshalled to COM interface
    /// </summary>
    internal unsafe struct SharedCcw_IVectorView
    {
        public System.IntPtr pfnQueryInterface;
        public System.IntPtr pfnAddRef;
        public System.IntPtr pfnRelease;
        public System.IntPtr pfnGetIids;
        public System.IntPtr pfnGetRuntimeClassName;
        public System.IntPtr pfnGetTrustLevel;

        public System.IntPtr pfnGetAt;
        public System.IntPtr pfnget_Size;
        public System.IntPtr pfnIndexOf;
        public System.IntPtr pfnGetMany;

        [PreInitialized]
        static SharedCcw_IVectorView s_theCcwVtable = new SharedCcw_IVectorView()
        {
            pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
            pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
            pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
            pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
            pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
            pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),

            // The 4 SharedCcw_IVectorView functions have exactly the same implementation as those in SharedCcw_IVector, just use them for free
            // The real difference is handled by IReadOnlyListThunk<T>
            pfnGetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(SharedCcw_IVector.GetAt),
            pfnget_Size = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(SharedCcw_IVector.get_Size),
            pfnIndexOf = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIndexOf>(SharedCcw_IVector.IndexOf),
            pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany1>(SharedCcw_IVector.GetMany),
        };

        public static System.IntPtr GetVtable()
        {
            return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
        }
    }

    /// <summary>
    /// Shared CCW for IVectorView<T> over IReadOnlyList<T> where T is blittable
    /// </summary>
    internal unsafe struct SharedCcw_IVectorView_Blittable
    {
        public System.IntPtr pfnQueryInterface;
        public System.IntPtr pfnAddRef;
        public System.IntPtr pfnRelease;
        public System.IntPtr pfnGetIids;
        public System.IntPtr pfnGetRuntimeClassName;
        public System.IntPtr pfnGetTrustLevel;

        public System.IntPtr pfnGetAt;
        public System.IntPtr pfnget_Size;
        public System.IntPtr pfnIndexOf;
        public System.IntPtr pfnGetMany;

        [PreInitialized]
        static SharedCcw_IVectorView_Blittable s_theCcwVtable = new SharedCcw_IVectorView_Blittable()
        {
            pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
            pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
            pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
            pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
            pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
            pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),

            // The 4 SharedCcw_IVectorView_Blittable functions have exactly the same implementation as those in SharedCcw_IVector_Blittable, just use them for free
            // The real difference is handled by IReadOnlyListBlittableThunk<T>
            pfnGetAt = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetSetInsertReplaceAll>(SharedCcw_IVector_Blittable.GetAt),
            pfnget_Size = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(SharedCcw_IVector_Blittable.get_Size),
            pfnIndexOf = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfIndexOf>(SharedCcw_IVector_Blittable.IndexOf),
            pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany1>(SharedCcw_IVector_Blittable.GetMany),
        };

        public static System.IntPtr GetVtable()
        {
            return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
        }
    }

    /// <summary>
    /// Shared CCW for IIterable<T> over IEnumerable<T> where T is a reference type marshalled to COM interface
    /// </summary>
    internal unsafe struct SharedCcw_IIterable
    {
        public System.IntPtr pfnQueryInterface;
        public System.IntPtr pfnAddRef;
        public System.IntPtr pfnRelease;
        public System.IntPtr pfnGetIids;
        public System.IntPtr pfnGetRuntimeClassName;
        public System.IntPtr pfnGetTrustLevel;

        public System.IntPtr pfnFirst;

        [PreInitialized]
        static SharedCcw_IIterable s_theCcwVtable = new SharedCcw_IIterable()
        {
            pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
            pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
            pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
            pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
            pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
            pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),

            pfnFirst = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(First),
        };

        public static System.IntPtr GetVtable()
        {
            return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
        }

        // Thunk function in \RH\src\tools\mcg\be\Templates\McgHelpers.cs due to dependency on EnumeratorToIteratorAdapter
        //    public static object IEnumerableThunk<T>(System.Collections.Generic.IEnumerable<T> enumerable)
        //    {
        //        return new EnumeratorToIteratorAdapter<T>(enumerable.GetEnumerator());
        //    }

        [NativeCallable]
        static int First(System.IntPtr pComThis, System.IntPtr pResult)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get enumerable
                object enumerable = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                Debug.Assert((interfaceType.GetInterfaceFlags() & McgInterfaceFlags.useSharedCCW) != 0);
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                // Create enumerator using thunk function
                object enumerator = CalliIntrinsics.Call<object>(thunk, enumerable);

                // Marshal to native iterator
                 *((IntPtr*)pResult) =  McgMarshal.ObjectToComInterface(enumerator, interfaceType.GetIteratorType());
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }
    }

    public static partial class Toolbox
    {
        public enum IIterator_Oper
        {
            get_Current,
            get_HasCurrent,
            MoveNext,
            GetMany
        };
    }


    /// <summary>
    /// Shared CCW for IIterator<T> over IIterator<T> where T is a reference type marshalled to COM interface
    /// </summary>
    internal unsafe struct SharedCcw_IIterator
    {
        public System.IntPtr pfnQueryInterface;
        public System.IntPtr pfnAddRef;
        public System.IntPtr pfnRelease;
        public System.IntPtr pfnGetIids;
        public System.IntPtr pfnGetRuntimeClassName;
        public System.IntPtr pfnGetTrustLevel;

        public System.IntPtr pfnget_Current;
        public System.IntPtr pfnget_HasCurrent;
        public System.IntPtr pfnMoveNext;
        public System.IntPtr pfnGetMany;

        [PreInitialized]
        static SharedCcw_IIterator s_theCcwVtable = new SharedCcw_IIterator()
        {
            pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
            pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
            pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
            pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
            pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
            pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),

            pfnget_Current = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_Current),
            pfnget_HasCurrent = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_HasCurrent),
            pfnMoveNext = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(MoveNext),
            pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany2>(GetMany),
        };

        public static System.IntPtr GetVtable()
        {
            return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
        }

        [NativeCallable]
        static int get_Current(System.IntPtr pComThis, System.IntPtr pValue)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get iterator
                object iterator = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object item = null;

                CalliIntrinsics.Call<int>(thunk, iterator, Toolbox.IIterator_Oper.get_Current, ref item, 0);

                *((IntPtr*)pValue) = McgMarshal.ObjectToComInterface(item, interfaceType.GetElementInterfaceType());
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static int get_HasCurrent(System.IntPtr pComThis, System.IntPtr pValue)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get iterator
                object iterator = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object item = null;
                *((byte*)pValue) = (byte)CalliIntrinsics.Call<int>(thunk, iterator, Toolbox.IIterator_Oper.get_HasCurrent, ref item, 0);
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static int MoveNext(System.IntPtr pComThis, System.IntPtr pValue)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get iterator
                object iterator = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object item = null;
                *((byte*)pValue) = (byte)CalliIntrinsics.Call<int>(thunk, iterator, Toolbox.IIterator_Oper.MoveNext, ref item, 0);
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static int GetMany(System.IntPtr pComThis, uint len, System.IntPtr pDest, System.IntPtr pCount)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get iterator
                object iterator = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object data = null;

                *((int*)pCount) = CalliIntrinsics.Call<int>(thunk, iterator, Toolbox.IIterator_Oper.GetMany, ref data, (int)len);

                System.IntPtr* dst = (System.IntPtr*)pDest;

                object[] src = data as object[];

                for (uint i = 0; i < len; i++)
                {
                    dst[i] = McgMarshal.ObjectToComInterface(src[i], interfaceType.GetElementInterfaceType());
                }
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }
    }

    /// <summary>
    /// Shared CCW for IIterator<T> over IIterator<T> where T is a blittable struct
    /// </summary>
    internal unsafe struct SharedCcw_IIterator_Blittable
    {
        public System.IntPtr pfnQueryInterface;
        public System.IntPtr pfnAddRef;
        public System.IntPtr pfnRelease;
        public System.IntPtr pfnGetIids;
        public System.IntPtr pfnGetRuntimeClassName;
        public System.IntPtr pfnGetTrustLevel;

        public System.IntPtr pfnget_Current;
        public System.IntPtr pfnget_HasCurrent;
        public System.IntPtr pfnMoveNext;
        public System.IntPtr pfnGetMany;

        [PreInitialized]
        static SharedCcw_IIterator_Blittable s_theCcwVtable = new SharedCcw_IIterator_Blittable()
        {
            pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
            pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
            pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
            pfnGetIids = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetIID>(__vtable_IInspectable.GetIIDs),
            pfnGetRuntimeClassName = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetRuntimeClassName),
            pfnGetTrustLevel = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(__vtable_IInspectable.GetTrustLevel),

            pfnget_Current = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_Current),
            pfnget_HasCurrent = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(get_HasCurrent),
            pfnMoveNext = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfTarget3>(MoveNext),
            pfnGetMany = AddrOfIntrinsics.AddrOf<AddrOfIntrinsics.AddrOfGetMany2>(GetMany),
        };

        public static System.IntPtr GetVtable()
        {
            return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
        }

        // public static Array IIteratorBlittableThunk<T>(IIterator<T> it, IIterator_Oper oper, ref T data, ref int len) where T : struct

        [NativeCallable]
        static int get_Current(System.IntPtr pComThis, System.IntPtr pValue)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get iterator
                object iterator = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int dummy = 0;
                CalliIntrinsics.Call<Array>(thunk, iterator, Toolbox.IIterator_Oper.get_Current, pValue, ref dummy);
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static int get_HasCurrent(System.IntPtr pComThis, System.IntPtr pValue)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get iterator
                object iterator = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int has = 0;
                CalliIntrinsics.Call<Array>(thunk, iterator, Toolbox.IIterator_Oper.get_HasCurrent, default(IntPtr), ref has);

                *((byte*)pValue) = (byte)has;
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static int MoveNext(System.IntPtr pComThis, System.IntPtr pValue)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get iterator
                object iterator = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int has = 0;
                CalliIntrinsics.Call<Array>(thunk, iterator, Toolbox.IIterator_Oper.MoveNext, default(IntPtr), ref has);

                *((byte*)pValue) = (byte)has;
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }

        [NativeCallable]
        static int GetMany(System.IntPtr pComThis, uint len, System.IntPtr pDest, System.IntPtr pCount)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get iterator
                object iterator = ComCallableObject.GetTarget(pComThis);

                // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                int count = (int)len;
                Array data = CalliIntrinsics.Call<Array>(thunk, iterator, Toolbox.IIterator_Oper.GetMany, default(IntPtr), ref count);

                *((uint*)pCount) = (uint)count;

                PInvokeMarshal.CopyToNative(data, 0, pDest, count);
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }
    }


    internal unsafe partial struct SharedCcw_AsyncOperationCompletedHandler
    {
        public System.IntPtr pfnQueryInterface;
        public System.IntPtr pfnAddRef;
        public System.IntPtr pfnRelease;

        public System.IntPtr pfnInvoke;

        [PreInitialized]
        static SharedCcw_AsyncOperationCompletedHandler s_theCcwVtable = new SharedCcw_AsyncOperationCompletedHandler()
        {
            pfnQueryInterface = AddrOfIntrinsics.AddrOf<AddrOfQueryInterface>(__vtable_IUnknown.QueryInterface),
            pfnAddRef = AddrOfIntrinsics.AddrOf<AddrOfAddRef>(__vtable_IUnknown.AddRef),
            pfnRelease = AddrOfIntrinsics.AddrOf<AddrOfRelease>(__vtable_IUnknown.Release),
            pfnInvoke = AddrOfIntrinsics.AddrOf<WinRTAddrOfIntrinsics.AddrOfTarget19>(Invoke),
        };

        public static System.IntPtr GetVtable()
        {
            return AddrOfIntrinsics.StaticFieldAddr(ref s_theCcwVtable);
        }

        [NativeCallable]
        static int Invoke(System.IntPtr pComThis, System.IntPtr _asyncInfo, int asyncStatus)
        {
            int hr = Interop.COM.S_OK;

            try
            {
                // Get enumerable
                object handler = ComCallableObject.GetTarget(pComThis);

               // Get thunk
                RuntimeTypeHandle interfaceType = ((__interface_ccw*)pComThis)->InterfaceType;
                IntPtr thunk = interfaceType.GetCcwVtableThunk();

                object asyncInfo =  McgMarshal.ComInterfaceToObject(_asyncInfo, interfaceType.GetAsyncOperationType());

                // Call handler.Invoke(asyncInfo, asyncStatus)
                CalliIntrinsics.Call<int>(thunk, handler, asyncInfo, asyncStatus);
            }
            catch (System.Exception hrExcep) when (McgMarshal.PropagateException(hrExcep))
            {
                hr = McgMarshal.GetHRForExceptionWinRT(hrExcep);
            }

            return hr;
        }
    }
#endif
}
